<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>面对对象 雪花效果</title>
</head>
<style>
    body {
        overflow: hidden;
        padding: 0;
        margin: 0;
        background: #000;
    }
</style>

<body>
    <canvas id="c"></canvas>
    <script>
        var getRandomColor = function() {
            return '#' + (Math.random() * 0xffffff << 0).toString(16);
        }
        var canvas = document.getElementById("c"),
            c = canvas.getContext("2d"),
            w = window.innerWidth,
            h = window.innerHeight,
            time = 20, // 转风向时间系数
            lr = 1, // 风向状态 +1 -1
            viewW = { // 实际下雪区域
                min: -1 / 2 * w,
                max: 3 / 2 * w
            },

            objArr = {}, // 雪花信息
            objArrLeng = 60; // 同时存在雪花数量
        jixueArr = [], // 积雪信息
            jixueH = 0, // 积雪高度
            jixueNum = 0.01, // 积雪累加系数
            objIndex = 0; // 雪花索引赋值
        canvas.width = w;
        canvas.height = h;

        function animate() {
            var randomX = Math.random() * (viewW.max - viewW.min) + viewW.min
            var size = (Math.random() * (20 - 2)) + 2
            objIndex++
            this.color = "#fff";
            this.x = randomX;
            this.size = size;
            this.y = 0;
            this.vx = 20;
            this.vy = this.size;
            this.id = objIndex;
            this.draw = function() {
                this.x += this.vx * (lr / time);
                this.y += this.vy;
                this.vy += 0.098
                c.fillStyle = this.color;
                c.beginPath();
                c.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
                c.shadowBlur = this.size / 2;
                c.shadowColor = "#ccc";
                c.fill();
                if (this.x < viewW.min || this.x > viewW.max || this.y <= 0 || this.y > canvas.height) {
                    jixueArr.push({
                        x: this.x,
                        y: h,
                        size: this.size + jixueH
                    })
                    delete objArr[this.id];
                }
            }
            objArr[this.id] = this;
        }
        var xx = 0.1

        function fn() {
            jixueH += jixueNum
            if (lr >= time || lr <= -time) {
                xx *= -1
            }
            lr += xx
            requestAnimationFrame(fn)
            if (Object.keys(objArr).length < objArrLeng) {
                new animate();

            }
            c.fillStyle = "#000";
            c.fillRect(0, 0, w, h);
            for (var key in objArr) {
                objArr[key].draw()
            }
            jixueArr.forEach(item => {
                c.beginPath();
                c.shadowBlur = 100;
                c.shadowColor = "#ccc";

                c.arc(item.x, item.y, item.size, 0, 2 * Math.PI);
                c.fill();
            })
            if (jixueArr.length >= 1000) {
                jixueArr.splice(0, 100)
            }
        }
        requestAnimationFrame(fn)
    </script>

</body>

</html>